package com.huishu.user.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huishu.commons.constant.WxConstact;
import com.huishu.commons.exception.BaseException;
import com.huishu.commons.pojo.Result;
import com.huishu.commons.pojo.dto.AddIntegrationDTO;
import com.huishu.commons.pojo.model.UserDO;
import com.huishu.commons.pojo.vo.UserMemberVO;
import com.huishu.commons.pojo.vo.UserOrderInfoVO;
import com.huishu.commons.utlis.*;
import com.huishu.user.config.YaDunMenmberApiInfoEntity;
import com.huishu.user.execl.UserExecl;
import com.huishu.user.fegin.CouponFeignClient;
import com.huishu.user.fegin.OrderFeignClient;
import com.huishu.user.mapper.UserMapper;
import com.huishu.user.pojo.dto.*;
import com.huishu.user.pojo.model.UserMemberDO;
import com.huishu.user.pojo.vo.ModifyUserVO;
import com.huishu.user.pojo.vo.UserPageListVO;
import com.huishu.user.service.UserMemberService;
import com.huishu.user.service.UserService;
import com.huishu.user.utils.AssistantContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author generator@ljj
 * @since 2023-04-06
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDO> implements UserService {

    @Autowired
    private UserMemberService userMemberService;

    @Autowired
    private YaDunMenmberApiInfoEntity yaDunMenmberApiInfoEntity;

    @Autowired
    private OrderFeignClient orderFeignClient;

    @Transactional
    @Override
    public UserDO weChatLogin(WeChatLoginDTO weChatLogin) {
        // 判断手机号是否已注册
        UserDO userInfo = baseMapper.selectOne(new QueryWrapper<UserDO>().lambda().and(obj -> obj
                .eq(UserDO::getPhone, weChatLogin.getUserPhone())
                .eq(UserDO::getIsDelete, 0)));
        if (userInfo == null) {
            userInfo = new UserDO();
            userInfo.setPhone(weChatLogin.getUserPhone());
            userInfo.setName(weChatLogin.getNickName());
            userInfo.setNickName(weChatLogin.getNickName());
            userInfo.setAvatar(weChatLogin.getAvatar());
            userInfo.setOpenId(weChatLogin.getOpenId());
            userInfo.setUnionId(weChatLogin.getUnionId());
            userInfo.setGender(weChatLogin.getGender());
            userInfo.setLoginTime(new Date());
            userInfo.setSalt(UuidUtils.getUUID());
            if (this.saveOrUpdate(userInfo)) {
                UserMemberHandle(userInfo);
                return userInfo;
            } else {
                log.info("微信注册插入数据失败");
                throw new BaseException("登录失败");
            }
        } else {
            updateUserMember(userInfo);
            userInfo.setUnionId(weChatLogin.getUnionId());
            userInfo.setOpenId(weChatLogin.getOpenId());
            userInfo.setLoginTime(new Date());
            userInfo.setSalt(UuidUtils.getUUID());
            this.updateById(userInfo);
            return userInfo;
        }
    }

    @Transactional
    @Override
    public UserDO registerOrLogin(UserRegisterOrLoginDTO registerOrLoginDTO) {
        UserDO userInfo = baseMapper.selectOne(new QueryWrapper<UserDO>().lambda().and(obj -> obj
                .eq(UserDO::getPhone, registerOrLoginDTO.getPhone())
                .eq(UserDO::getIsDelete, 0)));
        if (userInfo == null) {
            String openId = WechatUtil.getOpenId(registerOrLoginDTO.getCode());
            userInfo = new UserDO();
            userInfo.setPhone(registerOrLoginDTO.getPhone());
            userInfo.setName(registerOrLoginDTO.getPhone());
            userInfo.setNickName(registerOrLoginDTO.getPhone());
            userInfo.setAvatar(createAvatar(1));
            userInfo.setGender(3);
            userInfo.setSalt(UuidUtils.getUUID());
            userInfo.setLoginTime(new Date());
            userInfo.setOpenId(openId);
            if (this.saveOrUpdate(userInfo)) {
                UserMemberHandle(userInfo);
                return userInfo;
            } else {
                log.info("微信注册插入数据失败");
                throw new BaseException("登录失败");
            }
        } else {
            updateUserMember(userInfo);
            // 查询是否存在
            userInfo.setLoginTime(new Date());
            userInfo.setSalt(UuidUtils.getUUID());
            this.updateById(userInfo);
            return userInfo;
        }
    }


    @Override
    public Result addIntegration(AddIntegrationDTO addIntegrationDTO) {
        this.baseMapper.addIntegration(addIntegrationDTO);
        return Result.success();
    }

    @Override
    public Result<List<UserMemberVO>> findUserMember(List<Long> userIds) {
        List<UserDO> userDOS = this.baseMapper.selectBatchIds(userIds);
        LambdaQueryWrapper<UserMemberDO> queryWrapper = Wrappers.lambdaQuery(UserMemberDO.class)
                .in(UserMemberDO::getUserId, userIds);
        List<UserMemberDO> list = userMemberService.list(queryWrapper);
        Map<Long, UserMemberDO> collect = list.parallelStream().collect(Collectors.toMap(UserMemberDO::getUserId, userMemberDO -> userMemberDO));
        List<UserMemberVO> collect1 = userDOS.stream().map(userDO -> {
            UserMemberVO userMemberVO = BeanUtils.copyProperties(userDO, UserMemberVO.class);
            UserMemberDO userMemberDO = collect.get(userDO.getId());
            if (userMemberDO != null) {
                userMemberVO.setTierCode(userMemberDO.getTierCode());
                userMemberVO.setTierName(userMemberDO.getTierName());
            }
            userMemberVO.setUserId(userDO.getId());
            return userMemberVO;
        }).collect(Collectors.toList());
        return Result.success(collect1);
    }


    @Override
    public Result getOpenId(String code) {
        try {
            WechatUtil.WeChatParam weChatParam = new WechatUtil.WeChatParam(WxConstact.APPID, WxConstact.SECRET);
            JSONObject sessionKeyOpenId = WechatUtil.getSessionKeyOrOpenId(code, weChatParam);
            String openid = sessionKeyOpenId.getString("openid");
            String unionId = sessionKeyOpenId.getString("unionid");
            log.info("sessionKeyOpenId :{}", sessionKeyOpenId.toJSONString());
            if (StringUtils.isBlank(openid) && StringUtils.isBlank(unionId)) {
                return Result.fail("无效的 code");
            }
            LambdaUpdateWrapper<UserDO> uw = Wrappers.lambdaUpdate(UserDO.class)
                    .set(UserDO::getOpenId, openid)
                    .eq(UserDO::getId, AssistantContext.getCurrentUid());
            boolean update = this.update(uw);
            return update ? Result.success(openid) : Result.fail();
        } catch (IOException e) {
            e.printStackTrace();
        }
        throw new BaseException("获取openId失败");
    }

    @Transactional
    @Override
    public Result modify(UserDTO userDTO) {
        LambdaUpdateWrapper<UserDO> uw = Wrappers.lambdaUpdate(UserDO.class)
                .set(StringUtils.isNotEmpty(userDTO.getBirthday()), UserDO::getBirthday, userDTO.getBirthday())
                .set(UserDO::getGender, userDTO.getGender())
                .set(UserDO::getName, userDTO.getName())
                .set(UserDO::getSkinType, userDTO.getSkinType())
                .eq(UserDO::getId, AssistantContext.getCurrentUid());
        boolean update = this.update(uw);
        // 修改会员信息
        if (update) {
            LambdaQueryWrapper<UserMemberDO> queryWrapper = Wrappers.lambdaQuery(UserMemberDO.class)
                    .eq(UserMemberDO::getUserId, AssistantContext.getCurrentUid());
            UserMemberDO userMemberDO = userMemberService.getOne(queryWrapper);
            SyncMemberDTO syncMemberDTO = new SyncMemberDTO();
            syncMemberDTO.setUserId(AssistantContext.getCurrentUid());
            syncMemberDTO.setSync_type("2");
            syncMemberDTO.setMember_code(userMemberDO.getMemberCode());
            syncMemberDTO.setJoin_date(DateUtils.parseDateToStr(userMemberDO.getCreatedDate(), DateUtils.DATE_FORMAT_YYYY_MM_DD));
            syncMemberDTO.setName(userDTO.getName());
            syncMemberDTO.setBirthday(userDTO.getBirthday());
            syncMemberDTO.setMobile(userMemberDO.getMobile());
            syncMemberDTO.setGender(userDTO.getGender().toString());
            syncMemberDTO.setDatasource(userMemberDO.getDatasource());
            syncMemberDTO.setDescription(userDTO.getSkinType());
            yaDunMenberHandle(syncMemberDTO);
        }
        ModifyUserVO modifyUserVO = BeanUtils.copyProperties(userDTO, ModifyUserVO.class);
        modifyUserVO.setBirthday(this.getById(AssistantContext.getCurrentUid()).getBirthday());
        return Result.success(modifyUserVO);
    }

    @Override
    public Result updateAvatar(UserDTO userDTO) {
        LambdaUpdateWrapper<UserDO> uw = Wrappers.lambdaUpdate(UserDO.class)
                .set(UserDO::getAvatar, userDTO.getAvatar())
                .eq(UserDO::getId, AssistantContext.getCurrentUid());
        boolean update = this.update(uw);
        return update ? Result.success() : Result.fail();
    }


    @Override
    public Result pageList(UserPageListDTO userPageListDTO) {
        Page<UserPageListVO> page = new Page<UserPageListVO>(userPageListDTO.getCurrPage(), userPageListDTO.getPageSize());
        IPage<UserPageListVO> pageList = this.baseMapper.pageList(page, userPageListDTO);
        if (CollectionUtil.isEmpty(pageList.getRecords())) {
            return Result.success();
        }
        return Result.success(pageList);
    }


    @Override
    public void export(UserPageListDTO userPageListDTO, HttpServletResponse response) {
        int count = this.count();
        Page<UserPageListVO> page = new Page<UserPageListVO>(1, count);
        IPage<UserPageListVO> pageList = this.baseMapper.pageList(page, userPageListDTO);
        if (CollectionUtil.isEmpty(pageList.getRecords())) {
            throw new BaseException("无数据导出");
        }
        List<UserPageListVO> records = pageList.getRecords();
        List<UserExecl> userExecls = new ArrayList<>();
        threadsHandle(records, userExecls);
        ExportUtil.export(response, UserExecl.class, userExecls);
    }

    @Override
    public UserMemberDO getUserMemberInfo(String phone) {
        return getUserMember(phone);
    }

    @Transactional
    @Override
    public Result synchronizationData() {
        List<UserDO> list = this.list();
        for (UserDO userDO : list) {
            UserMemberDO userMember = getUserMember(userDO.getPhone());
            if (userMember != null) {
                LambdaQueryWrapper<UserMemberDO> queryWrapper = Wrappers.lambdaQuery(UserMemberDO.class)
                        .eq(UserMemberDO::getMobile, userDO.getPhone());
                UserMemberDO one = userMemberService.getOne(queryWrapper);
                userMember.setId(one.getId());
                userMemberService.updateById(userMember);
            }
        }
        return Result.success();
    }

    private void threadsHandle(List<UserPageListVO> records, List<UserExecl> orderExecls) {
        // 一百条为基准为一个线程处理
        List<List<UserPageListVO>> groupList = CommonUtils.partition(records, 100);
        CountDownLatch countDownLatch = new CountDownLatch(groupList.size());
        ExecutorService executorService = Executors.newFixedThreadPool(groupList.size());
        for (int i = 0; i < groupList.size(); i++) {
            int finalI = i;
            executorService.execute(() -> {
                List<UserPageListVO> productDOList = groupList.get(finalI);
                List<UserExecl> collect = productDOList.stream().map(userPageListVO -> {
                    UserExecl orderExecl = new UserExecl();
                    orderExecl.setName(userPageListVO.getName());
                    orderExecl.setPhone(userPageListVO.getPhone());
                    orderExecl.setTierName(userPageListVO.getTierName());
                    orderExecl.setPoints(userPageListVO.getPoints());
                    orderExecl.setIsNew(userPageListVO.getIsNew());
                    orderExecl.setOrderCount(userPageListVO.getOrderCount());
                    orderExecl.setTotalAmount(userPageListVO.getTotalAmount());
                    return orderExecl;
                }).collect(Collectors.toList());
                orderExecls.addAll(collect);
                countDownLatch.countDown();
            });
        }
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 关闭线程池
            executorService.shutdown();
        }
    }

    private void updateUserMember(UserDO userInfo) {
        UserMemberDO userMember = getUserMember(userInfo.getPhone());
        if (userMember != null) {
            LambdaQueryWrapper<UserMemberDO> queryWrapper = Wrappers.lambdaQuery(UserMemberDO.class)
                    .eq(UserMemberDO::getMobile, userInfo.getPhone());
            UserMemberDO one = userMemberService.getOne(queryWrapper);
            userMember.setId(one.getId());
            userMemberService.updateById(userMember);
            userInfo.setIsMember(1);
        }
    }

    private void UserMemberHandle(UserDO userInfo) {
        UserMemberDO userMember = getUserMember(userInfo.getPhone());
        if (userMember != null) {
            userMember.setUserId(userInfo.getId());
            userMember.setMobile(userInfo.getPhone());
            userMember.setIsNew(false);
            userMemberService.save(userMember);
            userInfo.setIsMember(1);
            this.updateById(userInfo);
        } else {
            SyncMemberDTO syncMemberDTO = new SyncMemberDTO();
            syncMemberDTO.setUserId(userInfo.getId());
            syncMemberDTO.setMobile(userInfo.getPhone());
            syncMemberDTO.setJoin_date(DateUtils.parseDateToStr(new Date(), DateUtils.DATE_FORMAT_YYYY_MM_DD));
            syncMemberDTO.setGender(userInfo.getGender().toString());
            syncMemberDTO.setSync_type("1");
            syncMemberDTO.setBirthday("1990-5-4");
            syncMemberDTO.setDatasource("28");
            syncMemberDTO.setName(userInfo.getName());
            yaDunMenberHandle(syncMemberDTO);
        }
    }

    private void yaDunMenberHandle(SyncMemberDTO syncMemberDTO) {
        String token = yaDunMenmberApiInfoEntity.getToken();
        syncMemberDTO.setToken(yaDunMenmberApiInfoEntity.getToken());
        String secret = yaDunMenmberApiInfoEntity.getSecret();
        long timestamp = Calendar.getInstance().getTimeInMillis();
        syncMemberDTO.setTimestamp(timestamp);
        String sign = MD5Utils.hexMd5(timestamp + token + secret);
        syncMemberDTO.setSign(sign);
        log.info(JSON.toJSONString(syncMemberDTO));
        JSONObject jsonObject = null;
        try {
            jsonObject = HttpUtils.doJsonPost(yaDunMenmberApiInfoEntity.getSyncMember(), JSON.toJSONString(syncMemberDTO), null);
            log.info("雅顿同步会员接口返回结果：{}", jsonObject);

            if (jsonObject.getString("code").equals("1000")) {
                if (syncMemberDTO.getSync_type().equals("1")) {
                    JSONObject data = jsonObject.getJSONObject("data");
                    String member_code = data.getString("member_code");
                    UserMemberDO userMemberDO = new UserMemberDO();
                    userMemberDO.setMemberCode(member_code);
                    userMemberDO.setUserId(syncMemberDTO.getUserId());
                    userMemberDO.setMobile(syncMemberDTO.getMobile());
                    userMemberDO.setName(syncMemberDTO.getName());
                    userMemberDO.setBirthday(syncMemberDTO.getBirthday());
                    userMemberDO.setGender(Integer.parseInt(syncMemberDTO.getGender()));
                    userMemberDO.setDatasource(syncMemberDTO.getDatasource());
                    userMemberDO.setIsNew(true);
                    UserMemberDO userMember = getUserMember(syncMemberDTO.getMobile());
                    userMemberDO.setTierName(userMember.getTierName());
                    userMemberDO.setTierCode(userMember.getTierCode());
                    userMemberService.save(userMemberDO);
                } else {
                    LambdaUpdateWrapper<UserMemberDO> uw = Wrappers.lambdaUpdate(UserMemberDO.class)
                            .set(UserMemberDO::getName, syncMemberDTO.getName())
                            .set(StringUtils.isNotEmpty(syncMemberDTO.getBirthday()), UserMemberDO::getBirthday, syncMemberDTO.getBirthday())
                            .set(UserMemberDO::getGender, syncMemberDTO.getGender())
                            .set(StringUtils.isNotEmpty(syncMemberDTO.getBirthday()), UserMemberDO::getIsUpdateBirthday, true)
                            .set(UserMemberDO::getDescription, syncMemberDTO.getDescription())
                            .eq(UserMemberDO::getUserId, syncMemberDTO.getUserId());
                    userMemberService.update(uw);
                }
            } else {
                if (!jsonObject.getString("code").equals("9008")) {
                    throw new BaseException("调用同步会员接口失败" + jsonObject.getString("message"));
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            log.error("调用同步会员接口失败:{}", e.getMessage());
        }
    }

    private String createAvatar(Integer gender) {
        if (gender == null) {
            return "http://file.gongpaipai.com/20201022/b04937b8ea921810d9d0ac5c60683fab.png";
        } else if (gender == 0) {
            return "http://file.gongpaipai.com/20201022/598b95b8cd1f302c58fe47fcb1f7bc11.png";
        } else {
            return "http://file.gongpaipai.com/20201022/a4221cd95949c9e3177c0d5108fe303a.png";
        }
    }

    private UserMemberDO getUserMember(String phone) {
        String token = yaDunMenmberApiInfoEntity.getToken();
        String secret = yaDunMenmberApiInfoEntity.getSecret();

        Map<String, Object> map = new HashMap<>();
        long timestamp = Calendar.getInstance().getTimeInMillis();
        map.put("timestamp", timestamp);
        map.put("token", token);
        String sign = MD5Utils.hexMd5(timestamp + token + secret);
        map.put("sign", sign);
        map.put("mobile", phone);
        log.info(JSON.toJSONString(map));

        JSONObject jsonObject = null;
        try {
            // yaDunMenmberApiInfoEntity.getUrl()
            jsonObject = HttpUtils.doJsonPost(yaDunMenmberApiInfoEntity.getQueryMemberForLeqee(), JSON.toJSONString(map), null);
            log.info("雅顿会员接口返回结果：{}", jsonObject);
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (jsonObject.getString("code").equals("9003")) {
            log.info("会员不存在进行注册！！");
            return null;
        }
        if (jsonObject.getString("code").equals("1000")) {
            JSONObject data = jsonObject.getJSONObject("data");
            UserMemberDO userMemberDO = new UserMemberDO();
            userMemberDO.setBirthday(data.getString("birthday"));
            userMemberDO.setDatasource(data.getString("datasource"));
            userMemberDO.setEmail(data.getString("email"));
            userMemberDO.setGender(data.getInteger("gender"));
            userMemberDO.setExpiredPoints(new BigDecimal(data.getString("expired_points") == null ? "0" : data.getString("expired_points")));
            userMemberDO.setJoinCounter(data.getString("join_counter"));
            userMemberDO.setManageCounter(data.getString("manage_counter"));
            userMemberDO.setTierName(data.getString("tier_name"));
            userMemberDO.setWechatUnionid(data.getString("wechat_unionid"));
            userMemberDO.setMemberCode(data.getString("member_code"));
            userMemberDO.setMobile(data.getString("mobile"));
            userMemberDO.setPoints(new BigDecimal(data.getString("points") == null ? "0" : data.getString("points")));
            userMemberDO.setName(data.getString("name"));
            userMemberDO.setTierGap(new BigDecimal(data.getString("tier_gap") == null ? "0" : data.getString("tier_gap")));
            userMemberDO.setTierCode(data.getString("tier_code"));
            return userMemberDO;
        }
        throw new BaseException("调用会员查询接口异常");
    }

    public static void main(String[] args) {
        //UserMemberDO userMember = getUserMember("15074150969");
        //System.out.println(JSON.toJSONString(userMember));
    }
}
